home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / vol6n10.arc / MAKEBAR.ASM < prev    next >
Assembly Source File  |  1987-05-11  |  46KB  |  1,390 lines

  1. ;======================================================================
  2. ;  MAKEBAR: read a bar-definition-file (.BDF) and produce a tokenized
  3. ;  .BAR file to be read by the TSR interpreter.
  4. ;----------------------------------------------------------------------
  5. CSEG    SEGMENT    PUBLIC    PARA    'CODE'
  6.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  7.         ORG    100H
  8. ENTPT:        JMP    MAIN
  9.  
  10. COPYRIGHT  DB  "MAKEBAR 1.0 (c) 1987, Ziff-Davis Publishing Corp",CR,LF,'$'
  11. AUTHOR       DB  1AH,"Robert L. Hummel"
  12.  
  13. ;======================================================================
  14. ;  EQUATES
  15. ;----------------------------------------------------------------------
  16. SPACE        EQU    20H            ;Some keys
  17. CR        EQU    0DH
  18. LF        EQU    0AH
  19. QUOTE        EQU    22H
  20. TAB        EQU    09H
  21.  
  22. INPUT_BUF_LEN    EQU    4000            ;Size constants
  23. OUTPUT_BUF_LEN    EQU    46000
  24. MENU_BUF_LEN    EQU    4000
  25. MENU_TBL_LEN    EQU    4000
  26. BUF_TOTAL = INPUT_BUF_LEN + OUTPUT_BUF_LEN + MENU_BUF_LEN + MENU_TBL_LEN
  27.  
  28. _SHIFT        EQU    1            ;Internal shift flags
  29. _CTRL        EQU    2
  30. _ALT        EQU    4
  31.  
  32.  
  33. ;----------------------------------------------------------------------
  34. ;  BUFFERS AND POINTERS
  35. ;----------------------------------------------------------------------
  36. INPUT_HNDL    DW    0            ;Handle of source file
  37. INPUT_HNDL_PTR    DW    0            ;Pointer to source file
  38. INPUT_BUF_END    DW    0FFFFH            ;Used by GET_CHAR
  39. OUTPUT_HNDL    DW    0            ;Handle of output file
  40. MENU_HEAD    DW    0            ;Pointer to current menu
  41. SHIFT_FLAGS    DB    0            ;Hold current shift state
  42.  
  43. ;----------------------------------------------------------------------
  44. ;  COUNTERS
  45. ;----------------------------------------------------------------------
  46. SOURCE_LINE    DW    0            ;For error messages
  47. NEW_REF        DB    -1            ;Two counters track menu
  48. OLD_REF        DB    0            ; references
  49.  
  50. ;----------------------------------------------------------------------
  51. ;  TABLES
  52. ;----------------------------------------------------------------------
  53. CMD_TABLE    LABEL    BYTE            ;All commands names
  54. _ASK        EQU    0            ; and their token values
  55. A_CMD        DB    'ASK',0
  56. _CR        EQU    1
  57. C_CMD        DB    'CR',0
  58. _EXECUTE    EQU    2
  59. E_CMD        DB    'EXECUTE',0
  60. _INPUT        EQU    3
  61. I_CMD        DB    'INPUT',0
  62. _MENU        EQU    4
  63. M_CMD        DB    'MENU',0
  64. _OPTION        EQU    5
  65. O_CMD        DB    'OPTION',0
  66. _PROGRAM    EQU    6
  67. P_CMD        DB    'PROGRAM',0
  68. _TYPE        EQU    7
  69. _CMD        DB    'TYPE',0
  70. _MEND        EQU    8
  71.         DB    'MEND',0
  72. _END        EQU    9
  73.         DB    'END',0
  74. _SEND        EQU    10
  75.         DB    0            ;End-of-table byte
  76. ;----------------------------------------------------------------------
  77. KEY_NAME_TBL    LABEL    BYTE            ;Special key names
  78.         DB    "S",0,"C",0,"A",0
  79.  
  80.         DB    "F1",0,"F2",0,"F3",0,"F4",0,"F5",0
  81.         DB    "F6",0,"F7",0,"F8",0,"F9",0,"F10",0
  82.  
  83.         DB    "ESC",0,"TAB",0,"ENTER",0,"BS",0
  84.  
  85.         DB    "HOME",0,"PGUP",0,"END",0,"PGDN",0,"INS",0
  86.         DB    "DEL",0,"U",0,"D",0,"L",0,"R",0,0
  87. ;----------------------------------------------------------------------
  88. ;  These keys may be combined with the CRTL and ALT keys
  89. ;----------------------------------------------------------------------
  90. KEY_TBL_1    DB    "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-=\[]",0
  91.  
  92. ;----------------------------------------------------------------------
  93. ;  CTRL combinations for 1234567890-= (use {c}1 for ; {c}3 for ")
  94. ;----------------------------------------------------------------------
  95. KEY_TBL_2    DW    003BH,0FE03H,0022H,0,0,001EH,0,0,0,0,001FH,0
  96.         DW    001CH, 001BH, 001DH
  97. ;----------------------------------------------------------------------
  98. ;  Scan codes for alpha keys a-z (used for ALT-alpha)
  99. ;----------------------------------------------------------------------
  100. KEY_TBL_3    DB    01EH,30H,2EH,20H,12H,21H,22H,23H,17H,24H,25H,26H
  101.         DB    32H,31H,18H,19H,10H,13H,1FH,14H,16H,2FH,11H,2DH
  102.         DB    15H,2CH
  103.  
  104. ;----------------------------------------------------------------------
  105. ;  SHIFT,CTRL for enter,bs,home,pgup,end,pgdn,ins,del,up,down,left,right
  106. ;----------------------------------------------------------------------
  107. KEY_TBL_4    DB    0DH,0FEH, 8,7FH, 47H,77H, 49H,84H, 4FH,75H
  108.         DB    51H,76H, 52H,0, 53H,0, 48H,0, 50H,0, 4BH,73H,4DH,74H
  109.  
  110. ;----------------------------------------------------------------------
  111. ;  FLAGS
  112. ;----------------------------------------------------------------------
  113. MENU_FLAG    DB    0        ;Non-zero when open menu blk
  114. OPTION_FLAG    DB    0        ;Non-zero when open option blk
  115. PROGRAM_NAME_FLAG DB    0        ;Non-zero when PROGRAM cmd read
  116.  
  117. ;----------------------------------------------------------------------
  118. ;  MESSAGES
  119. ;----------------------------------------------------------------------
  120. USAGE_MSG    DB    "Usage: MAKEBAR [path]input_file [path]output_file$"
  121. BAD_FILE_MSG    DB    "Can't Open File$"
  122. READ_MSG    DB    "Error Reading File$"
  123.  
  124. DUP_CMD_MSG    DB    "Duplicate Cmd$"
  125. CMD_ORDER_MSG    DB    "Cmd Out Of Order$"
  126. UNK_CMD_MSG    DB    "Unknown Cmd$"
  127.  
  128. NEST_MSG    DB    "MENU Without MEND$"
  129. SYNTAX_MSG    DB    "Syntax Error$"
  130. NO_NAME_MSG    DB    "Missing Name$"
  131. REF_MSG        DB    "Bad MENU Reference$"
  132. EOF_MSG        DB    "Missing END$"
  133. DEAD_KEY_MSG    DB    "Dead-Key or Bad Key$"
  134. LINE_MSG    DB    CR,LF,"Error At Line #       $"
  135. LINE_NUM_BUF    EQU    $-2
  136.  
  137. ;======================================================================
  138. ;  MENU FILE TOKENIZER - MAIN PROCEDURE
  139. ;----------------------------------------------------------------------
  140. MAIN        PROC    NEAR
  141.  
  142.         MOV    AH,9            ;Display string fn
  143.         MOV    DX,OFFSET COPYRIGHT    ;Say who we are
  144.         INT    21H            ; Thru DOS
  145.  
  146.         CLD                ;Strings moves forward
  147. ;----------------------------------------------------------------------
  148. ;  Check the file specs given on the command line.  Open the files and
  149. ;  save the file handles.
  150. ;----------------------------------------------------------------------
  151.         CALL    OPEN_FILES
  152.  
  153. ;----------------------------------------------------------------------
  154. ;  Read in the Menu-Definition-File and tokenize.  Write the output to
  155. ;  the new .BAR file for use with the resident interpreter.
  156. ;----------------------------------------------------------------------
  157.         CALL    TOKENIZE
  158.  
  159. ;----------------------------------------------------------------------
  160. ;  Close and update any open files.  Terminate gracefully.
  161. ;----------------------------------------------------------------------
  162.         CALL    CLOSE_FILES
  163.         MOV    AX,4C00H        ;Terminate process
  164.         INT    21H            ; Thru DOS
  165.  
  166. MAIN        ENDP
  167.  
  168. ;======================================================================
  169. ;  OPEN_FILES - Open the file given on the command line and the working
  170. ;  files needed during operation of the tokenizer.
  171. ;----------------------------------------------------------------------
  172. OPEN_FILES    PROC    NEAR
  173.  
  174.         MOV    SI,81H            ;Command line parameters
  175.         CALL    OPEN_A_FILE        ;Open source
  176.         MOV    INPUT_HNDL,AX        ;Save handle
  177.  
  178.         CALL    OPEN_A_FILE        ;Open destination file
  179.         MOV    OUTPUT_HNDL,AX        ;Save handle
  180.  
  181.         MOV    INPUT_BUF_END,0        ;Make refresh occur
  182.         RET
  183.  
  184. OPEN_FILES    ENDP
  185.  
  186. ;======================================================================
  187. ; OPEN_A_FILE - Read a string from the command line and attempt to open
  188. ;  it as a file.
  189. ;----------------------------------------------------------------------
  190. OPEN_CNT    DB    0            ;Switch for open function
  191.  
  192. OPEN_A_FILE    PROC    NEAR
  193.  
  194.         CALL    NON_WHITE        ;Point SI to 1st nonwhite
  195.         CMP    AL,CR            ;If not carriage return
  196.         JNE    HAVE_ARGS        ; go parse arguments
  197. NO_SPECS:
  198.         MOV    DX,OFFSET USAGE_MSG    ;Say how we are used
  199. OPEN_ERR:
  200.         JMP    ERROR_EXIT        ;Exit thru error procedure
  201. HAVE_ARGS:
  202.         PUSH    SI            ;Save start of string
  203.         CALL    WHITE            ;Point past end
  204.         MOV    CX,SI            ;End of string
  205.         POP    SI            ;Restore start
  206.         SUB    CX,SI            ;Get length of string
  207.         OR    CX,CX            ;If zero
  208.         JZ    NO_SPECS        ; no file names
  209.         MOV    DI,OFFSET PATH_BUF    ;Copy string here
  210.         REP    MOVSB            ; do it
  211.         XOR    AL,AL            ;Make ASCIIZ
  212.         STOSB                ; put in buffer
  213.  
  214. ;----------------------------------------------------------------------
  215. ;  Attempt to open the file.
  216. ;----------------------------------------------------------------------
  217.         MOV    AX,3D00H        ;Open file for reading
  218.         CMP    OPEN_CNT,0        ; if first file
  219.         JE    FILE_OPEN
  220.         DEC    AH            ;Create file if second
  221. FILE_OPEN:
  222.         MOV    DX,OFFSET PATH_BUF    ;Pathname of file
  223.         INT    21H            ;Handle in AX
  224.         JNC    SOURCE_OPEN        ;No carry if open OK
  225.         MOV    DX,OFFSET BAD_FILE_MSG
  226.         JMP    OPEN_ERR
  227. SOURCE_OPEN:
  228.         INC    OPEN_CNT        ;Change switch
  229.         RET
  230.  
  231. OPEN_A_FILE    ENDP
  232.  
  233. ;======================================================================
  234. ;  Close the files to update the length.
  235. ;----------------------------------------------------------------------
  236. CLOSE_FILES    PROC    NEAR
  237.  
  238.         MOV    AH,3EH            ;Close file function
  239.         MOV    BX,INPUT_HNDL        ; first file
  240.         INT    21H            ; Thru DOS
  241.  
  242.         MOV    AH,3EH            ;Close file function
  243.         MOV    BX,OUTPUT_HNDL        ; second file
  244.         INT    21H            ; Thru DOS
  245.         RET
  246.  
  247. CLOSE_FILES    ENDP
  248.  
  249. ;======================================================================
  250. ; TOKENIZE - Read and process the Bar Definition File (BDF).
  251. ;----------------------------------------------------------------------
  252. TOKENIZE    PROC    NEAR
  253.  
  254. ;----------------------------------------------------------------------
  255. ;  Clear flags and reset source line counter.
  256. ;----------------------------------------------------------------------
  257.         XOR    AX,AX            ;Zero
  258.         MOV    PROGRAM_NAME_FLAG,AL    ;No program name
  259.         MOV    MENU_FLAG,AL        ;Not inside MENU block
  260.         MOV    SOURCE_LINE,AX        ;Source line counter
  261.  
  262.         MOV    DI,OFFSET MENU_NAME_TBL    ;Fill the table with zeros
  263.         MOV    CX,MENU_TBL_LEN        ;Entire length
  264.         REP    STOSB            ; do it
  265.  
  266.         CALL    REFRESH_BUFFER        ;Load some chars into buf
  267.         MOV    DI,OFFSET OUTPUT_BUF    ;Init output buffer pointer
  268.  
  269. ;----------------------------------------------------------------------
  270. ;  Parse the input file to find commands and arguments.
  271. ;----------------------------------------------------------------------
  272. FIND_WORD:
  273.         CALL    NON_WHITE        ;Find non-white char
  274.         CMP    AL,CR            ;Ignore blank lines
  275.         JNE    TKN_1
  276.         CALL    NEXT_LINE        ;Skip to next line
  277.         JMP    FIND_WORD        ;Continue search
  278. TKN_1:
  279. ;----------------------------------------------------------------------
  280. ;  SI points to word.  Compare with known commands.  Return token in AL
  281. ;  or 0FFh if not recognized.
  282. ;----------------------------------------------------------------------
  283.         CALL    MAKEZ            ;Copy word at SI to buffer
  284.                         ; and make ASCIIZ
  285.         PUSH    SI            ;Preserve SI
  286.         MOV    SI,OFFSET CMD_TABLE    ;Look up word in this table
  287.         CALL    TABLE_LOOKUP        ;Compare cmd in buffer
  288.         POP    SI            ;AL = CMD # or FFh
  289.         CMP    AL,0FFH            ;Is error?
  290.         JNE    TKN_1A            ;No, valid CMD found
  291.         MOV    DX,OFFSET UNK_CMD_MSG
  292.         JMP    SHORT TKN_ERR
  293. TKN_1A:
  294. ;----------------------------------------------------------------------
  295. ;  If this is a PROGRAM statement, load the name of the program into the
  296. ;  buffer.  Must be the first command in the file.
  297. ;----------------------------------------------------------------------
  298.         CMP    PROGRAM_NAME_FLAG,0    ;Test if already had PROGRAM
  299.         PUSHF                ;Save result
  300.  
  301.         CMP    AL,_PROGRAM        ;Is this PROGRAM?
  302.         JE    TKN_2            ; yes, jump
  303.  
  304.         POPF                ;Did we have one?
  305.         JNZ    TKN_4            ; yes, try next cmd
  306.         JMP    TKN_7A            ; no, error
  307. TKN_2:
  308.         POPF                ; yes, Did we have one?
  309.         JZ    TKN_3            ;  No, this is first
  310.         MOV    DX,OFFSET DUP_CMD_MSG    ;  Yes, indicate error
  311.         JMP    SHORT TKN_ERR
  312. TKN_3:
  313. ;----------------------------------------------------------------------
  314. ;  Copy the name of the program to the output buffer.
  315. ;----------------------------------------------------------------------
  316.         MOV    BX,DI            ;Point BX to start of buf
  317.         MOV    AL,SPACE        ;Fill name with spaces
  318.         MOV    CX,10            ;10 chars
  319.         REP    STOSB            ;do it
  320.  
  321.         CALL    NEXT_WORD
  322.         CALL    TKN_STRING        ;Copy quoted string
  323.  
  324.         INC    PROGRAM_NAME_FLAG    ;Make flag non-zero
  325.         JMP    FIND_WORD        ;Get next command
  326. TKN_4:
  327. ;----------------------------------------------------------------------
  328. ;  END command terminates processing.
  329. ;----------------------------------------------------------------------
  330.         CMP    AL,_END            ;If not END, jump
  331.         JNE    TKN_4A
  332.  
  333.         MOV    AL,MENU_FLAG        ;If no open menus
  334.         OR    AL,OPTION_FLAG        ; or options
  335.         JZ    NO_OPENS        ; then clean up
  336. TKN_4AA:
  337.         MOV    DX,OFFSET NEST_MSG    ;Else, nesting error
  338.         JMP    SHORT TKN_ERR
  339. NO_OPENS:
  340.         MOV    AL,NEW_REF        ;If no unbalanced menu
  341.         OR    AL,OLD_REF        ; references
  342.         JZ    REFS_OK            ; write the results
  343.         MOV    DX,OFFSET REF_MSG    ;Else, error
  344. TKN_ERR:
  345.         JMP    ERROR_EXIT
  346. REFS_OK:
  347. ;----------------------------------------------------------------------
  348. ;  Flush the output buffer.
  349. ;----------------------------------------------------------------------
  350.         MOV    DX,OFFSET OUTPUT_BUF    ;Source buffer
  351.         MOV    CX,DI            ;End of buf
  352.         SUB    CX,DX            ; minus start = length
  353.         MOV    AH,40H            ;Write to file
  354.         MOV    BX,OUTPUT_HNDL        ; this handle
  355.         INT    21H            ;Thru DOS
  356.         RET                ;Return to top level
  357.  
  358. ;----------------------------------------------------------------------
  359. ;  Is this a command to start a MENU block?
  360. ;----------------------------------------------------------------------
  361. TKN_4A:
  362.         CMP    AL,_MENU
  363.         JNE    TKN_6            ;Jump if not MENU
  364.  
  365. ;----------------------------------------------------------------------
  366. ;  If we are already inside an active menu block, either an MEND is
  367. ;  missing or the menus are nested (both are errors).
  368. ;----------------------------------------------------------------------
  369.         CMP    MENU_FLAG,0
  370.         JNE    TKN_4AA            ;Jump if in block
  371.  
  372. ;----------------------------------------------------------------------
  373. ;  Execute MENU block startup code.  Point BX to a buffer where the
  374. ;  tokenized output will be temporarily stored.  When then menu block is
  375. ;  closed, the addresses in the menu header will be adjusted by the length
  376. ;  of the header.
  377. ;----------------------------------------------------------------------
  378. TKN_5:
  379.         MOV    BX,OFFSET MENU_BUF    ;Buffer for menu tokens
  380.         MOV    MENU_HEAD,DI        ;Location of menu header
  381.         XOR    AX,AX            ;Number of OPTIONS = 0
  382.         STOSW                ; placed in header (at DI)
  383.         INC    MENU_FLAG        ;Say we're inside menu
  384.  
  385. ;----------------------------------------------------------------------
  386. ;  Make sure the MENU command is followed by a name
  387. ;----------------------------------------------------------------------
  388.         CALL    NEXT_WORD        ;Point SI to next word
  389.         CMP    AL,CR            ;If CR, no name = error
  390.         JE    TKN_8A
  391. ;----------------------------------------------------------------------
  392. ;  If Menu name is in table, it was referenced by an earlier menu and
  393. ;  the address must be put back into that command line.  If it's not in
  394. ;  the table, add it and point to it's address.
  395. ;----------------------------------------------------------------------
  396.         CALL    MAKEZ            ;Change menu name to ASCIIZ
  397.         MOV    AX,MENU_HEAD        ;Signal says posting
  398.         SUB    AX,OFFSET OUTPUT_BUF    ;Make into offset
  399.         CALL    SEARCH_MENU_TABLE    ;Enter in table or resolve
  400.                         ; reference or error
  401.         CALL    NEXT_LINE        ;Skip to next line
  402.         JMP    FIND_WORD        ;Continue parsing
  403.  
  404. ;----------------------------------------------------------------------
  405. ;  If not a MENU command, must be inside a block to be valid.
  406. ;----------------------------------------------------------------------
  407. TKN_6:
  408.         CMP    MENU_FLAG,0
  409.         JE    TKN_7A            ;Jump if outside block
  410. TKN_7:
  411. ;----------------------------------------------------------------------
  412. ;  Inside a MENU block must reside a series of OPTION blocks.
  413. ;----------------------------------------------------------------------
  414.         CMP    OPTION_FLAG,0        ;Test if in option block
  415.         PUSHF                ; save result
  416.  
  417.         CMP    AL,_OPTION
  418.         JE    TKN_8            ;Jump if OPTION
  419.         POPF                ;Inside option block?
  420.         JNE    TKN_12            ;Jump if yes
  421. TKN_7A:
  422.         MOV    DX,OFFSET CMD_ORDER_MSG
  423.         JMP    TKN_ERR
  424. TKN_8:
  425.         POPF                ;Inside option block?
  426.         JE    NEW_OPTION_BLOCK    ;Jump if not
  427.  
  428. ;----------------------------------------------------------------------
  429. ;  Close this option block by adding the SEND command.
  430. ;----------------------------------------------------------------------
  431.         MOV    AL,_SEND        ;Send token
  432.         CALL    PUT_MENUBUF        ; to buffer
  433.  
  434. ;----------------------------------------------------------------------
  435. ;  To start new option block, increase the option counter.
  436. ;  Parse name and help line and point the pointers at them.
  437. ;----------------------------------------------------------------------
  438. NEW_OPTION_BLOCK:
  439.         INC    OPTION_FLAG        ;Inside option block
  440.         MOV    BP,MENU_HEAD        ;Number options this MENU
  441.         INC    WORD PTR [BP]        ; increase by 1
  442.  
  443. ;----------------------------------------------------------------------
  444. ;  Save the option name
  445. ;----------------------------------------------------------------------
  446.         CALL    NEXT_WORD        ;Point to OPTION NAME
  447.         CMP    AL,CR            ;Option must have name
  448.         JNE    TKN_9            ;Jump if name
  449. TKN_8A:
  450.         MOV    DX,OFFSET NO_NAME_MSG
  451.         JMP    TKN_ERR
  452. TKN_9:
  453.         CALL    MAKEZ            ;Make name at SI into ASCIIZ
  454.         MOV    AX,BX            ;Address where name is stored
  455.         SUB    AX,OFFSET MENU_BUF    ; from start of buffer
  456.         STOSW                ; is saved in menu header
  457.  
  458. ;----------------------------------------------------------------------
  459. ;  Copy the option name from the asciiz buffer to the menu buffer
  460. ;----------------------------------------------------------------------
  461.         PUSH    SI            ;Save register
  462.         MOV    SI,OFFSET PATH_BUF    ;Source for copy
  463. COPY_NAME:
  464.         LODSB                ;Get char
  465.         CALL    PUT_MENUBUF
  466.         OR    AL,AL            ;If not last byte
  467.         JNZ    COPY_NAME        ;continue copy
  468.         POP    SI            ;Restore register
  469.         CALL    NEXT_WORD        ;Look for help line
  470.  
  471. ;----------------------------------------------------------------------
  472. ;  HELP line is quoted string
  473. ;----------------------------------------------------------------------
  474. TKN_11:
  475.         MOV    AX,BX            ;Offset from start of buf
  476.         SUB    AX,OFFSET MENU_BUF    ; is location to put
  477.         STOSW                ; in header
  478.         CALL    TKN_STRING
  479.  
  480. ;----------------------------------------------------------------------
  481. ;  Put the offset where the tokenized commands will start into the header.
  482. ;----------------------------------------------------------------------
  483.         MOV    AX,BX            ;Current location
  484.         SUB    AX,OFFSET MENU_BUF    ; minus start is offset
  485.         STOSW                ;Put word
  486.         JMP    FIND_WORD
  487.  
  488. ;----------------------------------------------------------------------
  489. ;  The MEND command requires some cleanup to be performed.
  490. ;  The length of the header is calculated and added to the offsets in
  491. ;  the header.  Then the menu_buf is appended to the output_buf.
  492. ;----------------------------------------------------------------------
  493. TKN_12:
  494.         CMP    AL,_MEND
  495.         JNE    TKN_12AA        ;If not MEND, move on
  496. ;----------------------------------------------------------------------
  497. ;  Close out the option block (if there was one).
  498. ;----------------------------------------------------------------------
  499.         MOV    AL,_SEND        ;Write send token
  500.         CALL    PUT_MENUBUF
  501. ;----------------------------------------------------------------------
  502. ;  Flush the buffers.
  503. ;----------------------------------------------------------------------
  504.         PUSH    SI            ;Save register
  505.         MOV    SI,MENU_HEAD        ;Address of start of menu
  506.                         ; in the output file
  507.         LODSW                ;Number of entries in menu
  508.  
  509.         MOV    CX,AX            ;#Words = # entries * 3
  510.         SHL    CX,1            ; *2
  511.         ADD    CX,AX            ; +1 is same as *3
  512.  
  513.         JCXZ    APPEND_TOKENS        ;NULL menu bailout
  514.         PUSH    CX            ;Save number words to update
  515.         MOV    AX,CX            ;Length of offset
  516.         INC    AX            ; plus one
  517.         SHL    AX,1            ; times two
  518.  
  519.         MOV    CX,MENU_HEAD        ;Offset of start of menu
  520.         SUB    CX,OFFSET OUTPUT_BUF    ; from start of buf
  521.         ADD    AX,CX            ; plus length of header
  522.         POP    CX
  523. UPDATE_POINTERS:
  524.         ADD    WORD PTR [SI],AX    ; makes pointers correct
  525.         INC    SI            ;Skip to next pointer
  526.         INC    SI
  527.         LOOP    UPDATE_POINTERS
  528.  
  529. ;----------------------------------------------------------------------
  530. ;  Append the tokenized menu.
  531. ;----------------------------------------------------------------------
  532. APPEND_TOKENS:
  533.         MOV    CX,BX            ;End of menu buf
  534.         MOV    SI,OFFSET MENU_BUF    ;start of menu buf
  535.         SUB    CX,SI            ;# bytes to transfer
  536.         REP    MOVSB            ;do it
  537.         POP    SI            ;restore register
  538.  
  539. ;----------------------------------------------------------------------
  540. ;  Reset the flags.
  541. ;----------------------------------------------------------------------
  542.         MOV    MENU_FLAG,0
  543.         MOV    OPTION_FLAG,0
  544.         JMP    FIND_WORD        ;get next command
  545.  
  546. ;----------------------------------------------------------------------
  547. ;  Deal with commands other than PROGRAM, MENU, and OPTION
  548. ;----------------------------------------------------------------------
  549. TKN_12AA:
  550.         CALL    PUT_MENUBUF        ;Put the token in the file
  551.         CMP    AL,_EXECUTE        ;If not execute
  552.         JNE    TKN_13            ; move on
  553.  
  554. ;----------------------------------------------------------------------
  555. ;  EXECUTE command references another menu.  Let the SEARCH_MENU_TABLE
  556. ;  routine satisfy the reference, or leave a "wanted" message.
  557. ;----------------------------------------------------------------------
  558.         CALL    NEXT_WORD        ;Point to named menu
  559.         CMP    AL,CR            ;End of line?
  560.         JNE    TKN_12A
  561.         JMP    TKN_8A            ;(out of range jump)
  562. TKN_12A:
  563.         CALL    MAKEZ            ;Put name in buffer
  564.         MOV    AX,0FFFFH        ;= want address
  565.         CALL    SEARCH_MENU_TABLE    ;Try and resolve
  566.         JMP    FIND_WORD
  567.  
  568. ;----------------------------------------------------------------------
  569. ;  Separate out commands that take arguments.
  570. ;----------------------------------------------------------------------
  571. TKN_13:
  572.         CMP    AL,_ASK            ;Ask takes string
  573.         JE    TKN_17
  574.         CMP    AL,_TYPE        ;So does type
  575.         JE    TKN_17
  576.         JMP    FIND_WORD        ;Token already in, so go
  577.  
  578. ;----------------------------------------------------------------------
  579. ;  These commads require the quoted string following them to be included
  580. ;  as an ASCIIZ string following the command byte.
  581. ;----------------------------------------------------------------------
  582. TKN_17:
  583.         CALL    NEXT_WORD        ;Point to string
  584.         CALL    TKN_STRING        ;Copy it
  585.         JMP    FIND_WORD
  586.  
  587. TOKENIZE    ENDP
  588.  
  589. ;======================================================================
  590. ;  AX points to an ASCIIZ string.  Look up that string in table pointed
  591. ;  to by SI to see if we can find a match.
  592. ;----------------------------------------------------------------------
  593. TABLE_LOOKUP    PROC    NEAR
  594.  
  595.         PUSH    DI            ;Save registers
  596.         PUSH    CX
  597.         PUSH    DX
  598.  
  599.         XOR    CL,CL            ;Command counter
  600. CL_0:
  601.         CMP    BYTE PTR [SI],0        ;End of table?
  602.         JNZ    CL_2            ; jump if not
  603.         MOV    CL,0FFH            ;Signal error
  604. CL_1:
  605.         MOV    AL,CL            ;Return cmd number
  606.         POP    DX            ;Restore registers
  607.         POP    CX
  608.         POP    DI
  609.         RET
  610. CL_2:
  611.         MOV    DI,AX            ;Pointer to unknown command
  612.         CALL    STR_CMP            ;NC if matched
  613.         JNC    CL_1
  614.         INC    CL            ;Point to next
  615.         JMP    CL_0            ;Test for table end
  616.  
  617. TABLE_LOOKUP    ENDP
  618.  
  619. ;======================================================================
  620. ;  Compare strings at DI,SI where SI is a table.
  621. ;----------------------------------------------------------------------
  622. STR_CMP        PROC    NEAR
  623. STR_1:
  624.         MOV    DL,[DI]            ;Get char from string
  625.         INC    DI            ;Point to next
  626.         MOV    DH,[SI]            ;Get char from table
  627.         INC    SI            ;Point to next
  628.         CMP    DH,DL            ;If equal
  629.         JE    STR_3            ; jump
  630.         DEC    SI            ;Backup in table
  631. STR_2:
  632.         MOV    DH,[SI]            ;Examine char in table
  633.         INC    SI            ;Goto next char
  634.         OR    DH,DH            ;Is it end of entry?
  635.         JNZ    STR_2            ; no, continue scanning
  636.         STC                ; return with failure
  637.         RET
  638. STR_3:
  639.         OR    DX,DX            ;If both not 0
  640.         JNZ    STR_1            ; continue compare
  641.         CLC                ; else, they match
  642.         RET
  643.  
  644. STR_CMP        ENDP
  645.  
  646. ;======================================================================
  647. ;  This procedure prints an error message and indicates the source line
  648. ;  number on which it occured.
  649. ;----------------------------------------------------------------------
  650. ERROR_EXIT    PROC    NEAR
  651.  
  652.         MOV    AH,9            ;Print the error message
  653.         INT    21H            ; Thru DOS
  654.  
  655.         MOV    DI,OFFSET LINE_NUM_BUF    ;Put line number here
  656.         MOV    AX,SOURCE_LINE        ;Contains line number
  657.         MOV    BX,10            ;Base 10 numbers
  658. LINE_LOOP:
  659.         XOR    DX,DX            ;Divide DX:AX by BX
  660.         DIV    BX
  661.         ADD    DL,30H            ;Make number into ASCII
  662.         MOV    [DI],DL            ;Save it
  663.         DEC    DI            ;Move toward more significant
  664.         OR    AX,AX            ;If remainder not 0
  665.         JNZ    LINE_LOOP        ; continue
  666.  
  667.         MOV    DX,OFFSET LINE_MSG    ;Write message
  668.         MOV    AH,9            ;Display string fn
  669.         INT    21H            ; Thru DOS
  670.  
  671.         CALL    CLOSE_FILES        ;Close files and terminate
  672.         MOV    AX,4CFFH        ; with error=255
  673.         INT    21H            ; Thru DOS
  674.  
  675. ERROR_EXIT    ENDP
  676.  
  677. ;======================================================================
  678. ;  Position SI to the begining of the next word.
  679. ;----------------------------------------------------------------------
  680. NEXT_WORD    PROC    NEAR
  681.  
  682.         CALL    IS_WHITE        ;Is current char white?
  683.         JNC    NW_1            ; yes, jump
  684.         CALL    WHITE            ; no, find first white
  685. NW_1:
  686.         CALL    NON_WHITE        ;Scan for first non-white
  687.         RET
  688.  
  689. NEXT_WORD    ENDP
  690.  
  691. ;======================================================================
  692. ;  Enter with SI pointing to string.  Position so SI points at first
  693. ;  delimiter character AFTER the present char.  Return char in AL.
  694. ;  AL changed, SI moved by file routines.
  695. ;----------------------------------------------------------------------
  696. WHITE        PROC    NEAR
  697.  
  698.         MOV    AL,[SI]            ;Check current char
  699.         CMP    AL,CR            ; for EOL
  700.         JE    W_RET            ; and leave
  701. W_LOOP:
  702.         CALL    GET_CHAR        ;Get the next char
  703.         CMP    AL,CR            ;If EOL
  704.         JE    W_RET            ; return
  705.         CALL    IS_WHITE        ;Returns NC if white
  706.         JC    W_LOOP
  707. W_RET:
  708.         RET
  709. WHITE        ENDP
  710.  
  711. ;======================================================================
  712. ;  Enter with SI pointing to string.  Position so SI points at first
  713. ;  non-delimiter character AFTER the present char.  Return char in AL.
  714. ;  AL changed, SI moved by file routines.
  715. ;----------------------------------------------------------------------
  716. NON_WHITE    PROC    NEAR
  717.  
  718.         MOV    AL,[SI]            ;Check current char
  719.         CMP    AL,CR            ; for EOL
  720.         JE    NW_RET            ; and leave
  721. NW_LOOP:
  722.         CALL    GET_CHAR        ;Get the next char
  723.         CMP    AL,CR            ;If EOL
  724.         JE    NW_RET            ; return
  725.         CALL    IS_WHITE        ;Returns NC if white
  726.         JNC    NW_LOOP
  727. NW_RET:
  728.         RET
  729. NON_WHITE    ENDP
  730.  
  731. ;======================================================================
  732. ;  Examine Char at SI and return CY if non-white, NC if delimiter
  733. ;  Only flags changed.
  734. ;----------------------------------------------------------------------
  735. DELIMS        DB    " ,:",LF,TAB        ;White chars
  736.  
  737. IS_WHITE    PROC    NEAR
  738.  
  739.         PUSH    AX            ;Save registers
  740.         PUSH    CX
  741.         PUSH    DI
  742.  
  743.         MOV    AL,[SI]            ;Examine current char
  744.         MOV    CX,5            ;Number delims to compare
  745.         MOV    DI,OFFSET DELIMS    ;Here they are
  746.         REPNE    SCASB            ;Compare them
  747.         CLC                ;NC if delimiter
  748.         JZ    IW_1            ;ZR indicates match found
  749.         STC                ; else CY
  750. IW_1:
  751.         POP    DI            ;Restore registers
  752.         POP    CX
  753.         POP    AX
  754.         RET
  755.  
  756. IS_WHITE    ENDP
  757.  
  758. ;======================================================================
  759. ;  Make the character in AL UPPER case.
  760. ;----------------------------------------------------------------------
  761. MAKE_UC        PROC    NEAR
  762.  
  763.         CMP    AL,'a'            ;If between a and z
  764.         JB    UC_1
  765.         CMP    AL,'z'
  766.         JA    UC_1
  767.         SUB    AL,20H            ;Make upper case
  768. UC_1:
  769.         RET
  770. MAKE_UC        ENDP
  771.  
  772. ;======================================================================
  773. ;  Position SI to the next char after a CR.  Start search with current
  774. ;  char.
  775. ;----------------------------------------------------------------------
  776. NEXT_LINE    PROC    NEAR
  777.  
  778.         MOV    AL,[SI]            ;Examine current char
  779. NL_1:
  780.         CMP    AL,CR            ;Is it CR?
  781.         JE    NL_2            ; yes, jump
  782.         CALL    GET_CHAR        ; no, get next char
  783.         JMP    NL_1            ;  and try again
  784. NL_2:
  785.         CALL    GET_CHAR        ;Go to first char after CR
  786.         RET
  787.  
  788. NEXT_LINE    ENDP
  789.  
  790. ;======================================================================
  791. ;    This proc helps resolve references to other menus made with
  792. ;  EXECUTE commands.  If entered with AX=FFFF, the calling procedure has
  793. ;  a reference it needs to satisfy.  If an address has been entered in
  794. ;  the table for that name, the address is returned and the reference is
  795. ;  satisfied.  If not, a "IOU" is inserted in the table.
  796. ;    If entered with AX != FFFFh, the calling procedure is supplying the
  797. ;  starting address of the MENU named at PATH_BUF, and asking that these
  798. ;  be entered into the table to satisfy a reference.  If the name is found
  799. ;  in the table, left in a previous bookmark, the reference is satisfied
  800. ;  and the entry is marked "USED". Any further use of that name generates
  801. ;  an error.
  802. ;    For a forward reference, the structure is:
  803. ;        ASCIIZ string
  804. ;        WORD - Address of the start of the menu that
  805. ;            contains the reference (menu_head)
  806. ;        WORD - Offset from the end of menu header that
  807. ;            is the destination for the fix-up
  808. ;    For a POST:
  809. ;        ASCIIZ string
  810. ;        WORD - Address in output file of menu
  811. ;        WORD - 0FFFFh
  812. ;  Possibilities:
  813. ;    1) Post a MENU not previously requested
  814. ;    2) Post a MENU previously requested
  815. ;    3) Request a MENU previously posted
  816. ;    4) Ask for a MENU not previously posted
  817. ;----------------------------------------------------------------------
  818. SEARCH_MENU_TABLE    PROC    NEAR
  819.  
  820.         PUSH    SI            ;Save used registers
  821.         PUSH    DI
  822.         PUSH    DX
  823.         PUSH    CX
  824.  
  825. ;----------------------------------------------------------------------
  826. ;  AX=FFFF if request.  AX != FFFF, then post the MENU address.
  827. ;----------------------------------------------------------------------
  828.         CMP    AX,0FFFFH        ;Switch = FFFF if request
  829.         JE    WANT_ADR        ; to satisfy reference
  830.  
  831. ;----------------------------------------------------------------------
  832. ;  AX contains the output file offset of a menu to post in this table.
  833. ;  If the name is in the table, it was referenced earlier and we can go
  834. ;  back and fix it up.  If the name is NOT in the table, post it.
  835. ;----------------------------------------------------------------------
  836.         CALL    MENU_LOOK        ;Changes SI
  837.         JNC    SMT_7            ;Match was found if NC
  838.  
  839. ;----------------------------------------------------------------------
  840. ;  1) Post a menu not previously requested. No match found.  Create a
  841. ;  new entry for this menu.  SI points to end of table.
  842. ;  Copy the name from the buffer to the menu table.
  843. ;----------------------------------------------------------------------
  844.         INC    NEW_REF            ;Add a new reference
  845.         MOV    CX,0FFFFH        ;POST code
  846. SMT_1:
  847.         MOV    DI,OFFSET PATH_BUF    ;Name of MENU is here
  848. ;----------------------------------------------------------------------
  849. ;  Copy menu name to menu_name_table
  850. ;----------------------------------------------------------------------
  851. SMT_5:
  852.         MOV    DL,[DI]            ;Get char in DL
  853.         INC    DI            ;Point to next
  854.         MOV    [SI],DL            ;Save this char in table
  855.         INC    SI            ;next destination
  856.         OR    DL,DL            ;Was that last byte?
  857.         JNZ    SMT_5            ; no, get more
  858.  
  859. ;----------------------------------------------------------------------
  860. ;  Make AX into offset from buffer start.  Save in menu table.
  861. ;  CX contains either offset from menu_buf of reference or FFFF (POST).
  862. ;----------------------------------------------------------------------
  863.         MOV    WORD PTR [SI],AX    ;Menu at this address
  864.         MOV    WORD PTR [SI][2],CX
  865.         JMP    SHORT SMT_EXIT        ;clean up
  866.  
  867. ;----------------------------------------------------------------------
  868. ;  2) Post a MENU previously requested.  SI points past the ASCIIZ name
  869. ;  in the table to the location of the forward reference.
  870. ;----------------------------------------------------------------------
  871. SMT_7:
  872.         INC    OLD_REF            ;Add an old reference
  873.         MOV    DX,WORD PTR [SI][2]    ;2nd word
  874.         CMP    DX,0FFFFH        ; if POST, two menus have
  875.         JE    SMT_7B            ; the same name (error)
  876.         CMP    DX,0FFFEH        ;Already referenced
  877.         JNE    SMT_8            ; is also an error
  878. SMT_7B:
  879.         MOV    DX,OFFSET REF_MSG    ;error
  880.         JMP    ERROR_EXIT
  881. SMT_8:
  882. ;----------------------------------------------------------------------
  883. ;  SI points to address of menu as offset from start of buffer.
  884. ;  SI+2 points to additional offset from end of header.
  885. ;  Address of reference is [si] + 2 + 3 * 2 * [[si]] + [si+2] !
  886. ;----------------------------------------------------------------------
  887.         MOV    DI,WORD PTR [SI]    ;Offset into output_buf
  888.         ADD    DI,OFFSET OUTPUT_BUF    ;Absolute memory location
  889.         MOV    CX,WORD PTR [DI]    ;Number of entries in header
  890.         SHL    CX,1            ; 2 bytes per word
  891.         ADD    DI,CX
  892.         INC    CX            ; 2 for first word
  893.         SHL    CX,1
  894.         ADD    DI,CX
  895.  
  896.         ADD    DI,WORD PTR [SI][2]
  897.         MOV    [DI],AX            ; reference satisfied
  898.         MOV    WORD PTR [SI][2],0FFFEH    ;Mark this entry USED
  899.         JMP    SHORT SMT_EXIT        ;Clean up
  900.  
  901. ;----------------------------------------------------------------------
  902. ;  Try and satisfy a reference.
  903. ;----------------------------------------------------------------------
  904. WANT_ADR:
  905.         CALL    MENU_LOOK        ;CY if no match
  906.         JC    SMT_9
  907.  
  908. ;----------------------------------------------------------------------
  909. ;  3) Request a MENU previously posted.  Entry name was in table.
  910. ;----------------------------------------------------------------------
  911.         DEC    NEW_REF
  912.         MOV    DX,WORD PTR [SI][2]    ;Second word
  913.         CMP    DX,0FFFFH        ; should contain POST code
  914.         JNE    SMT_7B            ;if not, ERROR!
  915.  
  916.         MOV    AX,[SI]            ;Get address of menu
  917.         CALL    PUT_MENUBUF        ;Put lower byte
  918.         MOV    AL,AH
  919.         CALL    PUT_MENUBUF        ;Put upper byte
  920.  
  921.         MOV    WORD PTR [SI][2],0FFFEH    ;Mark entry used
  922.         JMP    SHORT SMT_EXIT
  923.  
  924. ;----------------------------------------------------------------------
  925. ;  4) Ask for a MENU not previously posted.  Put an IOU in the table.
  926. ;----------------------------------------------------------------------
  927. SMT_9:
  928.         DEC    OLD_REF
  929.         MOV    AX,MENU_HEAD        ;First entry is offset of
  930.         SUB    AX,OFFSET OUTPUT_BUF    ; requesting menu
  931.  
  932.         MOV    CX,BX            ;Second entry is offset past
  933.         SUB    CX,OFFSET MENU_BUF    ; the menu header
  934.  
  935.         ADD    BX,2            ;Leave room for address
  936.         JMP    SMT_1            ;Go create table entry
  937. SMT_EXIT:
  938.         POP    CX            ;Restore registers
  939.         POP    DX
  940.         POP    DI
  941.         POP    SI
  942.         RET
  943.  
  944. SEARCH_MENU_TABLE    ENDP
  945.  
  946. ;======================================================================
  947. ;  Look for a name in the menu.  If carry is set, no match was found
  948. ;  and SI points to the end of the table.  If carry is clear, match was
  949. ;  found and SI points to address word after entry.
  950. ;  SI is changed.
  951. ;----------------------------------------------------------------------
  952. MENU_LOOK    PROC    NEAR
  953.  
  954.         PUSH    DI            ;Save registers
  955.         PUSH    DX
  956.  
  957.         MOV    SI,OFFSET MENU_NAME_TBL    ;Known names
  958. ML_1:
  959.         CMP    BYTE PTR [SI],0        ;If 0, end of table
  960.         JNE    ML_3            ; else compare entry
  961.         STC                ;signal error
  962. ML_2:
  963.         POP    DX            ;Restore registers
  964.         POP    DI
  965.         RET
  966. ML_3:
  967.         MOV    DI,OFFSET PATH_BUF    ;Name to find
  968.         CALL    STR_CMP            ;CY if no match
  969.         JNC    ML_2            ;Return result
  970.         ADD    SI,4            ;Skip past addresses
  971.         JMP    ML_1            ;Check next table entry
  972.  
  973. MENU_LOOK    ENDP
  974.  
  975. ;======================================================================
  976. ;  Interpret the contents of the quoted string and write to output buffer.
  977. ;  Entered with SI pointing to the beginning quote.  An illegal character
  978. ;  or combination produces an error and terminates processing.
  979. ;----------------------------------------------------------------------
  980. TKN_STRING    PROC    NEAR
  981.  
  982.         CMP    BYTE PTR [SI],QUOTE    ;Must point to quoted string
  983.         JNE    TS_ERR            ; or syntax error.
  984.  
  985.         PUSH    DI            ;Save used register
  986. TS_1:
  987.         MOV    SHIFT_FLAGS,0        ;Clear shift flags
  988. TS_1AA:
  989.         CALL    GET_CHAR        ;Get next char
  990.         CMP    AL,CR            ;If not CR
  991.         JNE    TS_QUOTE        ; go to next test
  992. TS_ERR:
  993.         JMP    SC_ERR            ;Report a syntax error
  994. TS_QUOTE:
  995.         CMP    AL,QUOTE        ;If quote
  996.         JNE    TS_1A
  997. TS_EXIT:
  998.         XOR    AL,AL            ; make string asciiz
  999.         CALL    PUT_MENUBUF        ; and write to buffer
  1000.  
  1001.         CALL    NEXT_LINE        ;Position to next line
  1002.         POP    DI            ;Restore register
  1003.         RET                ; and leave
  1004. TS_1A:
  1005.         CMP    AL,"{"            ;Key name follows
  1006.         JE    SPEC_CHAR        ;Go snif it out
  1007.  
  1008.         CMP    SHIFT_FLAGS,0        ;If any shift keys on
  1009.         JNE    DO_XLAT            ; do translation
  1010.         XOR    AH,AH            ;Else, ASCII output of AL
  1011.  
  1012. ;----------------------------------------------------------------------
  1013. ;  If AH=0, output the code in AL; If AH != 0, output AH, then AL.
  1014. ;----------------------------------------------------------------------
  1015. OUTPUT_CODE:
  1016.         OR    AH,AH            ;If AH=0
  1017.         JZ    OC_1            ; output AL only
  1018.         XCHG    AH,AL            ;Switch
  1019.         CALL    PUT_MENUBUF        ;Write the high byte
  1020.         XCHG    AH,AL            ;restore AL
  1021. OC_1:
  1022.         CALL    PUT_MENUBUF        ;Put AL in buffer
  1023.         JMP    TS_1            ;Get another character
  1024.  
  1025. ;----------------------------------------------------------------------
  1026. ;  These keys may be valid with CTRL and ALT, but not SHIFT
  1027. ;----------------------------------------------------------------------
  1028. DO_XLAT:
  1029.         CMP    SHIFT_FLAGS,_SHIFT    ;Is SHIFT on?
  1030.         JNE    TS_1B
  1031. DEAD_KEY_ERROR:
  1032.         MOV    DX,OFFSET DEAD_KEY_MSG    ;Invalid key combo
  1033.         JMP    ERROR_EXIT
  1034. TS_1B:
  1035. ;----------------------------------------------------------------------
  1036. ;  See if the key is in the table.
  1037. ;----------------------------------------------------------------------
  1038.         CALL    MAKE_UC            ;Make upper case
  1039.  
  1040.         MOV    AH,AL            ;Save original char
  1041.         MOV    DI,OFFSET KEY_TBL_1    ;Source for compare
  1042.         MOV    CX,DI            ;Save start of table
  1043. TS_2:
  1044.         MOV    AL,[DI]            ;Get char from table
  1045.         INC    DI            ;Point to next
  1046.         OR    AL,AL            ;If 0, AL was illegal char
  1047.         JE    DEAD_KEY_ERROR
  1048.         CMP    AL,AH            ;Do we have a match?
  1049.         JNE    TS_2            ;No, try again
  1050.         DEC    DI            ;Backup pointer
  1051.         MOV    AX,DI            ;Have a match if here
  1052.         SUB    AX,CX            ;Offset into table
  1053.  
  1054. ;----------------------------------------------------------------------
  1055. ; Found a match.  Tediously calculate output byte.
  1056. ;----------------------------------------------------------------------
  1057.         CMP    AL,25            ;If A-Z
  1058.         JBE    IS_ALPHA        ; process as alpha keys
  1059.         SUB    AL,26            ;Remove alpha bias
  1060.  
  1061.         CMP    SHIFT_FLAGS,_CTRL    ;Go perform CTRL combos
  1062.         JE    TS_4
  1063.                         ;These are ALT combos
  1064.         CMP    AL,11
  1065.         JA    DEAD_KEY_ERROR        ;Too high
  1066.         ADD    AX,0FE78H        ;Output 2 bytes
  1067.         JMP    OUTPUT_CODE
  1068. TS_4:                        ;CTRL combos
  1069.         SHL    AL,1            ;multiply by 2
  1070.         MOV    DI,OFFSET KEY_TBL_2
  1071.         ADD    DI,AX            ;Find word in table
  1072.         MOV    AX,[DI]            ;Load into AX
  1073.         OR    AX,AX            ;If zero
  1074.         JZ    DEAD_KEY_ERROR        ; this combo not allowed
  1075.         JMP    OUTPUT_CODE        ; else write it
  1076.  
  1077. ;----------------------------------------------------------------------
  1078. ;  CTRL/ALT alphabet combinations.
  1079. ;----------------------------------------------------------------------
  1080. IS_ALPHA:
  1081.         CMP    SHIFT_FLAGS,_ALT
  1082.         JE    TS_5
  1083.         INC    AL            ;ALT is simple, add 1
  1084.         JMP    OUTPUT_CODE
  1085. TS_5:
  1086.         MOV    DI,OFFSET KEY_TBL_3    ;CTRL keys combos
  1087.         ADD    DI,AX            ;Add offset to
  1088.         MOV    AL,[DI]            ; get char code
  1089.         MOV    AH,0FEH            ;Signal extended ASCII
  1090.         JMP    OUTPUT_CODE        ;Send it to buffer
  1091.  
  1092. ;----------------------------------------------------------------------
  1093. ;  Here the {strings} are translated to their equivalent keystrokes.
  1094. ;  Move the key name into the ASCIIZ buffer.
  1095. ;----------------------------------------------------------------------
  1096. SPEC_CHAR:
  1097.         MOV    DI,OFFSET PATH_BUF
  1098. SC_1:
  1099.         CALL    GET_CHAR        ;Get char inside brace
  1100.  
  1101.         CMP    AL,'{'            ;If doubled, use {
  1102.         JNE    SC_2            ;Jump for other chars
  1103.         CMP    DI,OFFSET PATH_BUF    ;If = no chars have been
  1104.         JE    OC_1            ; processed yet. {{
  1105. SC_ERR:
  1106.         MOV    DX,OFFSET SYNTAX_MSG
  1107.         JMP    ERROR_EXIT
  1108. SC_2:
  1109.         CMP    AL,QUOTE        ;If char is quote
  1110.         JE    SC_ERR
  1111.  
  1112.         CMP    AL,'}'            ;Close brace?
  1113.         JE    SC_3            ; go search table
  1114.         CALL    MAKE_UC            ;Make Upper case
  1115.         STOSB                ;Put char in buffer
  1116.         JMP    SC_1            ;Continue to copy key name
  1117. SC_3:
  1118.         XOR    AL,AL            ;Make asciiz
  1119.         STOSB
  1120.         PUSH    SI            ;Save register
  1121.         MOV    SI,OFFSET KEY_NAME_TBL    ;Search this table
  1122.         MOV    AX,OFFSET PATH_BUF    ; for this entry
  1123.         CALL    TABLE_LOOKUP
  1124.         POP    SI            ;Restore register
  1125.  
  1126. ;----------------------------------------------------------------------
  1127. ;  Return # of entry in table or FFh if not found.
  1128. ;----------------------------------------------------------------------
  1129.         CMP    AL,0FFH
  1130.         JE    SC_ERR
  1131.  
  1132.         OR    AL,AL            ;0 = Turn SHIFT on
  1133.         JNZ    SC_4
  1134.         MOV    SHIFT_FLAGS,_SHIFT
  1135.         JMP    TS_1AA
  1136. SC_4:
  1137.         DEC    AL            ;0 = Turn CTRL on
  1138.         JNZ    SC_5
  1139.         MOV    SHIFT_FLAGS,_CTRL
  1140.         JMP    TS_1AA
  1141. SC_5:
  1142.         DEC    AL            ;0 = Turn ALT on
  1143.         JNZ    SC_6
  1144.         MOV    SHIFT_FLAGS,_ALT
  1145.         JMP    TS_1AA
  1146.  
  1147. ;----------------------------------------------------------------------
  1148. ;  Test for the Function keys (40 combinations).
  1149. ;----------------------------------------------------------------------
  1150. SC_6:
  1151.         DEC    AL            ;Adjust key number
  1152.         CMP    AL,9            ;Keys 0-9
  1153.         JA    SC_10            ;Can't be function key
  1154.         ADD    AL,3BH            ;Key code
  1155.         MOV    AH,SHIFT_FLAGS        ;Test for shift states
  1156.         CMP    AH,_SHIFT        ;For shift
  1157.         JNE    SC_7
  1158.         ADD    AL,19H            ;Add 19h
  1159. SC_7:
  1160.         CMP    AH,_CTRL        ;For CTRL
  1161.         JNE    SC_8
  1162.         ADD    AL,23H            ;Add 23h
  1163. SC_8:
  1164.         CMP    AH,_ALT            ;For ALT
  1165.         JNE    SC_9
  1166.         ADD    AL,2DH            ;Add 2dh
  1167. SC_9:
  1168.         MOV    AH,0FEH            ;Say this is extended ascii
  1169.         JMP    OUTPUT_CODE        ;Dump the bytes
  1170.  
  1171. ;----------------------------------------------------------------------
  1172. ;  ALT is not allowed for these keys.
  1173. ;----------------------------------------------------------------------
  1174. SC_10:
  1175.         CMP    SHIFT_FLAGS,_ALT    ;If Alt's not on
  1176.         JNE    SC_10B            ; jump
  1177. SC_10A:
  1178.         JMP    DEAD_KEY_ERROR        ; else, error
  1179. SC_10B:
  1180.         SUB    AL,10            ;Eliminate BIAS
  1181.         JNZ    SC_11
  1182.         MOV    AL,01BH            ;ESC key
  1183.         JMP    OC_1
  1184. SC_11:
  1185.         DEC    AL            ;TAB key
  1186.         JNZ    SC_13
  1187.         CMP    SHIFT_FLAGS,0        ;Any shift keys on?
  1188.         JE    SC_12            ; no, jump
  1189.         CMP    SHIFT_FLAGS,_SHIFT    ;SHIFT only is allowed
  1190.         JNE    SC_10A            ; else error
  1191.         MOV    AX,0FE0FH        ;SHIFT-TAB
  1192.         JMP    OUTPUT_CODE        ;to output
  1193. SC_12:
  1194.         MOV    AL,9            ;Normal TAB
  1195. SC_12A:
  1196.         JMP    OC_1
  1197.  
  1198. ;----------------------------------------------------------------------
  1199. ;  These keys are the same alone or with SHIFT, but CTRL is different.
  1200. ;----------------------------------------------------------------------
  1201. SC_13:
  1202.         DEC    AL            ;Remove bias
  1203.         XOR    AH,AH            ;Zero AH
  1204.         MOV    DI,OFFSET KEY_TBL_4    ;Table of SHIFT/CTRL values
  1205.         SHL    AX,1            ;Make into offset
  1206.         ADD    DI,AX            ; from start of table
  1207.         MOV    DH,SHIFT_FLAGS        ;If CTRL
  1208.         CMP    DH,_CTRL
  1209.         JNE    SC_14
  1210.         INC    DI            ; move one byte further
  1211. SC_14:
  1212.         MOV    DL,[DI]            ;Get char from table
  1213.         OR    DL,DL            ; =0 if illegal
  1214.         JZ    SC_10A
  1215.         XCHG    AL,DL            ;Put offset in DL
  1216.         CMP    DL,2            ;What key?
  1217.         JE    SC_12A            ;If BS, all ascii
  1218.         JA    SC_15            ;above, all extended
  1219.         CMP    DH,_CTRL        ;CTRL-ENTER is special
  1220.         JNE    SC_12A
  1221. SC_15:
  1222.         MOV    AH,0FEH            ;Add extended code
  1223.         JMP    OUTPUT_CODE
  1224.  
  1225. TKN_STRING    ENDP
  1226.  
  1227. ;======================================================================
  1228. ;  Read from the BDF file into a buffer.  If an EOF is found, perform
  1229. ;  the final cleanup and return to the main procedure.
  1230. ; (must also keep track of file pointer and signal when EOF)
  1231. ;----------------------------------------------------------------------
  1232. REFRESH_BUFFER    PROC    NEAR
  1233.  
  1234.         PUSH    BX
  1235.         PUSH    CX
  1236.         PUSH    DX
  1237.  
  1238.         MOV    AH,42H            ;Move file pointer
  1239.         XOR    AL,AL            ; offset from begining
  1240.         MOV    BX,INPUT_HNDL        ;File handle
  1241.         XOR    CX,CX            ;Offset CX:DX
  1242.         MOV    DX,INPUT_HNDL_PTR
  1243.         INT    21H            ;Thru DOS
  1244.         JC    READ_ERR
  1245.  
  1246. ;----------------------------------------------------------------------
  1247. ;  Fill buffer.
  1248. ;----------------------------------------------------------------------
  1249.         MOV    AH,3FH            ;Read from handle fn
  1250.         MOV    BX,INPUT_HNDL
  1251.         MOV    CX,INPUT_BUF_LEN    ;Number bytes to read
  1252.         MOV    SI,OFFSET INPUT_BUF
  1253.         MOV    DX,SI            ;DS:DX destination
  1254.  
  1255.         CMP    [INPUT_HNDL_PTR],0    ;If start of file
  1256.         JNE    NOT_FIRST_READ
  1257.         MOV    BYTE PTR [SI],20H    ;Make a current char
  1258.         DEC    CX            ;Read one less byte
  1259.         INC    DX            ;New destination
  1260. NOT_FIRST_READ:
  1261.         INT    21H            ;Thru DOS
  1262.         JNC    READ_OK
  1263. READ_ERR:
  1264.         MOV    DX,OFFSET READ_MSG
  1265.         JMP    ERROR_EXIT
  1266. READ_OK:
  1267.         ADD    INPUT_HNDL_PTR,AX    ;Add bytes read
  1268.         SUB    DX,SI            ;Calculate ending address
  1269.         ADD    AX,DX            ; of our buffer
  1270.         MOV    INPUT_BUF_END,AX    ; and save it
  1271.  
  1272.         POP    DX            ;Restore registers
  1273.         POP    CX
  1274.         POP    BX
  1275.         RET
  1276.  
  1277. REFRESH_BUFFER    ENDP
  1278.  
  1279. ;======================================================================
  1280. ;  Copy the word at SI into a buffer and make it asciiz
  1281. ;----------------------------------------------------------------------  
  1282. MAKEZ        PROC    NEAR
  1283.  
  1284.         PUSH    DI
  1285.         MOV    DI,OFFSET PATH_BUF    ;Destination
  1286.         PUSH    DI
  1287. MZ_1:
  1288.         CALL    IS_WHITE        ;Examine char at SI
  1289.         JNC    MZ_2
  1290.  
  1291.         MOV    AL,[SI]            ;Get the char
  1292.         CMP    AL,CR            ;Is it CR?
  1293.         JE    MZ_2            ; yes, terminate string
  1294.         CALL    MAKE_UC            ; else, change to lower case
  1295.         STOSB                ;  save at DI
  1296.         CALL    GET_CHAR        ;Get next char
  1297.         JMP    MZ_1
  1298. MZ_2:
  1299.         XOR    AL,AL            ;Make ASCIIZ
  1300.         STOSB
  1301.  
  1302.         POP    AX            ;Return buffer address
  1303.         POP    DI            ;Restore pointer
  1304.         RET
  1305.  
  1306. MAKEZ        ENDP
  1307.  
  1308. ;======================================================================
  1309. ;  Get a char from the input buffer.  If past the end of the buffer,
  1310. ;  refresh the buffer.  Check for EOF (SI = INPUT_BUF_END != BUF_LEN)
  1311. ;  If comments are detected, they are weeded out.
  1312. ;----------------------------------------------------------------------
  1313. COMMENT_FLAG    DB    0            ;=1 if inside comment
  1314.  
  1315. GET_CHAR    PROC    NEAR
  1316. ;----------------------------------------------------------------------
  1317. ;  Check buffer for pointer past end.
  1318. ;----------------------------------------------------------------------
  1319.         PUSH    AX            ;Save register
  1320.         INC    SI            ;Advance pointer
  1321.         MOV    AX,SI            ;Current location
  1322.         SUB    AX,OFFSET INPUT_BUF    ; minus start
  1323.         CMP    AX,INPUT_BUF_END    ; longer than allowed
  1324.         POP    AX            ;(restore pointer)
  1325.         JB    GC_1            ; no need to refresh
  1326.         CALL    REFRESH_BUFFER        ;Attempt to load buffer
  1327.  
  1328. ;----------------------------------------------------------------------
  1329. ;  AX contains the number of chars read.  If AX=0, unexpected EOF.
  1330. ;----------------------------------------------------------------------
  1331.         OR    AX,AX            ;# chars read
  1332.         JNZ    GC_1            ;jump if not 0
  1333.         MOV    DX,OFFSET EOF_MSG
  1334.         JMP    ERROR_EXIT
  1335.  
  1336. ;----------------------------------------------------------------------
  1337. ;  check for, and eliminate comments
  1338. ;----------------------------------------------------------------------
  1339. GC_1:
  1340.         MOV    AL,[SI]            ;Get new char
  1341.         CMP    AL,CR            ;If new line
  1342.         JNE    GC_3
  1343.         MOV    COMMENT_FLAG,0        ; reset comment
  1344.         INC    SOURCE_LINE        ; next line
  1345. GC_2:
  1346.         CMP    COMMENT_FLAG,0        ;If inside comment
  1347.         JNE    GET_CHAR        ; read until CR
  1348.         RET
  1349. GC_3:
  1350.         CMP    AL,';'            ;If this isn't a comment
  1351.         JNE    GC_2            ; then continue
  1352.         INC    COMMENT_FLAG        ;else read until CR
  1353.         JMP    GET_CHAR
  1354.  
  1355. GET_CHAR    ENDP
  1356.  
  1357. ;======================================================================
  1358. PUT_MENUBUF    PROC    NEAR
  1359.  
  1360.         MOV    [BX],AL            ;Write byte to [bx]
  1361.         INC    BX            ;Move pointer
  1362.         RET
  1363.  
  1364. PUT_MENUBUF    ENDP
  1365.  
  1366. ;======================================================================
  1367. ;  Buffer Allocation area
  1368. ;----------------------------------------------------------------------
  1369. PC        =    $
  1370. LAST_BYTE    =    PC
  1371.  
  1372. PATH_BUF    =    PC            ;DB 64 DUP (?)
  1373. PC        =    PC + 64
  1374.  
  1375. INPUT_BUF    =    PC            ;DB INPUT_BUF_LEN DUP(?)
  1376. PC        =    PC + INPUT_BUF_LEN
  1377.  
  1378. OUTPUT_BUF    =    PC            ;DB OUTPUT_BUF_LEN DUP(?)
  1379. PC        =    PC + OUTPUT_BUF_LEN
  1380.  
  1381. MENU_BUF    =    PC            ;DB MENU_BUF_LEN DUP(?)
  1382. PC        =    PC + MENU_BUF_LEN
  1383.  
  1384. MENU_NAME_TBL    =    PC            ;DB MENU_TBL_ELN DUP(?)
  1385. PC        =    PC + MENU_TBL_LEN
  1386.  
  1387. ;----------------------------------------------------------------------
  1388. CSEG    ENDS
  1389.     END    ENTPT
  1390.